package circularBufferProducerConsumerLock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Buffer {
	final Lock lock = new ReentrantLock();

	final Condition notFull = lock.newCondition();
	final Condition notEmpty = lock.newCondition();

	private int size;
	private int end;
	private int start;
	private Object[] data;

	public Buffer(int size) {

		this.size = size + 1;
		data = new Object[this.size];
		start = 1;
		end = 0;
	}

	public void push(Object value) {

		lock.lock();

		try {
			while (isFull()) {

				try {
					notFull.await();
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
				System.err.println("Producer is waiting" + '\n');
			}

			if (start == size - 1) {
				data[start] = value;
				start = 0;
			} else {
				data[start++] = value;
			}
			notEmpty.signalAll();
		} finally {
			lock.unlock();
		}
	}

	public Object pop() {

		lock.lock();

		try {
			while (isEmpty()) {
				try {
					notEmpty.await();
				} catch (InterruptedException e) {

					e.printStackTrace();
				}
				System.err.println("Consumer is waiting" + '\n');
			}
			Object value;
			if (end == size - 1) {
				end = 0;
				value = data[end];
			} else {
				value = data[++end];
				data[end] = null;
			}
			notFull.signalAll();
			return value;
		} finally {
			lock.unlock();
		}
	}

	public boolean isEmpty() {
		if (start - 1 == end || end - start == size - 1) {
			return true;
		} else {
			return false;
		}

	}

	public boolean isFull() {
		return start == end;

	}

}
